/*
 * @文件描述: 
 * @版本: 
 * @作者: 周晨阳
 * @Date: 2021-01-13 23:31:59
 */
#include "VoltageMeter.h"
#include "myADC.h"
/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/
#define OPEN 1
#define CLOSED 0
//外围电路电阻值，单位k，参见电路图pdf中的电阻标注，实际焊接时根据所测得电阻填写
#define R7 (1000.0f)
#define R11 (6.8f)
//限幅算法防抖动 ，闸值
#define X10_GATE 3
#define X1_GATE 5
//需要多少个数据一起做平均
#define AVR_NUM 1000

/**************自定义到此为止**************/

//加法电路提升的电压，大概在1.1v左右
#define REF_VOLTAGE (R46 / (R45 + R46)) * VCC

//衰减系数，大概在1/148左右
#define DAMPING_FACTOR (R11 / (R7 + R11))
#define ZERO 0.0000001f

/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/
//电压表开关状态
static unsigned char state;
// adc输出值
static float raw_value = 0;
//真实电压值，
static float voltage;
//同样是电压值，但是会自适应到最适合的数值，并匹配相应的单位
static float AdjVoltage;
//当前单位
static unsigned char unit;
//放大器的放大倍数
static int ampFactor;

static float inputData[AVR_NUM];
//static float outputData[AVR_NUM];

static uint8_t dataReady = 0;
static int dataPointer = 0;
static float lastVoltage = 0;

/* Private function prototypes -----------------------------------------------*/

/* Private functions ---------------------------------------------------------*/
void setCallbackFunc(void (*cb)(uint16_t))
{
    setADCxCallbackFun(0, cb);
}

/**
 * @description: 电压表初始化
 * @param {type}
 * @return {type}
 */
void VoltageMeterInit()
{

    VoltageADC_GPIO_Init();
    //放大器增益默认为x1
    ampFactor = 1;
#ifndef NO_BOARD
    printf("VoltageMeter is in normal mode\n");
#else
    printf("VoltageMeter is in NO_BOARD mode\n");
#endif

    printf("VoltageMeter Init  done...\n");
}
/**
 * @description: //adc数值更新的回调函数
 * @param {type}
 * @return {type}
 */
static void AdcInterrupt(uint16_t value)
{
    //更新数值
    //MultiMeter_ADC_Stop();

    raw_value = value;

    if (dataPointer < AVR_NUM)
    {
        dataReady = 0;
        inputData[dataPointer] = (float)value;
        dataPointer++;
        //MultiMeter_ADC_Start();
    }
    else
    {
        MultiMeter_ADC_Stop();
        dataReady = 1;
    }

#ifdef ADC_RAW_VALUE
    printf("voltageMeter ADC raw :%d \n", value);
#endif
}
/**
 * @description: 开启电压表
 * @param {type}
 * @return {type}
 */
void openVoltageMeter()
{
#ifndef WIN_SIM
    MultiMeter_ADCx_Init_auto(ADC2, VOLTAGE_ADC_CHANNEL);

#endif // !WIN_SIM

    setCallbackFunc(AdcInterrupt);
    MultiMeter_ADC_Start();
    state = OPEN;

#ifdef DEBUG_MODE
    printf("voltageMeter is open\n");
#endif
}
/**
 * @description: 关闭电压表
 * @param {type}
 * @return {type}
 */
void closeVoltageMeter()
{

    MultiMeter_ADC_Stop();
    //取消回调函数
    setCallbackFunc(NULL);
    // GPIO_ResetBits(VOLTAGE_GPIO_PORT, VOLTAGE_GPIO_PIN);
    //添加相应的硬件代码，如关闭adc，继电器等
    state = CLOSED;

#ifdef DEBUG_MODE
    printf("voltageMeter is closed\n");
#endif
}
/**
 * @brief : 获取原始电压值
 * @param {*}
 * @return {*}
 */
float getRawVlotage()
{
    return voltage;
}
/**
 * @description: 取得电压值，配合getU_Unit使用，用于直接驱动屏幕显示
 * 主要步骤为：取得原始电压值->fir滤波->限幅滤波->校准->缩放数值到合适大小->完成
 * @param {type}
 * @return {type}
 */
float getVoltage()
{
    return AdjVoltage;
}
/**
 * @description: 获得当前数值的单位
 * @param {type}
 * @return {type}
 */
unsigned char getU_Unit()
{

    if (state)
    {
        if (fabs(voltage) - 1.0f > ZERO)
        {

            return UNIT_V;
        }
        else if (fabs(voltage) - 1.0f < ZERO && fabs(voltage) - 0.001f > ZERO)
        {
            // voltage*1000.0f;
            return UNIT_MV;
        }
        else if (fabs(voltage) - 0.001f < ZERO)
        {
            // voltage*1000000.0f;
            return UNIT_UV;
        }
        else
        {
            return UNIT_V;
        }
    }
    else
    {
        return 0;
    }
}
/**
 * @description: 改变放大器的放大倍数
 * @param {int} factor
 * @return {*}
 */
void changeVoltageFactor(int factor) { ampFactor = factor; }
/**
 * @description: 获得当前放大器的放大倍数
 * @param {*}
 * @return {*}
 */
int getVoltageFactor() { return ampFactor; }
/**
 * @brief : 获取当前档位下指针应该指向的角度
 * @param {*}
 * @return {*}
 */
float getNiddelAngle()
{
    float angle;

    if (ampFactor == 10)
    {
        angle = (11.9f / 5.0f) * voltage;
    }
    else
    {
        angle = (11.9f / 50.0f) * voltage;
    }
    if (angle > 36.5f)
    {
        angle = 36.5;
    }
    if (angle < -36.5f)
    {
        angle = -36.5f;
    }

    return angle;
}

/**
 * @brief: 数值更新函数
 * @param {type}
 * @return {type}
 */
void VoltageMeterLooper()
{
    int l;
    float adjVoltage;
    float fabsVoltage;
    float adcVoltage;
    float realVoltage;
    float maxDiff = 0;
    static float lastMaxDiff = 0;

    if (!state && dataReady == 0)
    {
        return;
    }
    dataReady = 0;
#ifndef SIMULATE_VALUE

#ifndef NO_BOARD

/**************FIR滤波算法+算数平均算法***********/
#ifdef USE_FIR

    //firFilterFloat(inputData, outputData, AVR_NUM);
    dataPointer = 0;

    for (l = 0; l < AVR_NUM; l++)
    {
        realVoltage += inputData[l];
    }
    realVoltage /= (float)AVR_NUM;

    // printf("adc raw:%d,avr:%d\n", (int)inputData[0], (int)realVoltage);
/*加入限幅滤波算法，防止数字不停抖动,闸值在头文件定义*/
#ifdef ANTI_INTERFERENCE

    if (ampFactor == 1)
    {
        if (fabs(realVoltage - lastVoltage) < X1_GATE)
        {
            realVoltage = lastVoltage;
        }
        else
        {
            lastVoltage = realVoltage;
        }
    }
    else if (ampFactor == 10)
    {
        if (fabs(realVoltage - lastVoltage) < X10_GATE)
        {
            realVoltage = lastVoltage;
        }
        else
        {
            lastVoltage = realVoltage;
        }
    }

#else
    lastVoltage = realVoltage;
#endif
    /***********限幅滤波算法结束***********************/

    adcVoltage = (realVoltage / 4096.0f) * 3.3f;
    //计算后外部设备的实际电压
    realVoltage =
        ((adcVoltage / 1.5f) - REF_VOLTAGE) / (DAMPING_FACTOR * ampFactor);
#else
    // // adc实测电压
    adcVoltage = (raw_value / 4096.0f) * 3.3f;

    // //计算后外部设备的实际电压
    realVoltage =
        ((adcVoltage / 1.5f) - REF_VOLTAGE) / (DAMPING_FACTOR * ampFactor);
#endif
/**************FIR滤波算法+算数平均算法结束***********/

// NO_BOARD 宏开启时执行
#else
    float realVoltage = (raw_value / 4096.0f) * 3.3f;
#endif

    voltage = realVoltage;

#else
    voltage = 5.12f;

#endif
    printf("raw voltage:%f\n", voltage);

/************校准算法*******************/
#ifdef USE_CALIBRATION

    //需要使用较为标准的仪器来校准

    // x10档的拟合函数
    // y= 0.9557x + 0.3328

#define X1 0.9557f
#define X0 0.3328f

    // x1档的拟合函数
    // y = 1.0475634 x + 5.2787842 R² = 0.9999826

#define X3 1.0475634f
#define X2 5.2787842f

    if (ampFactor == 10)
    {
        voltage = X1 * voltage + X0;
    }
    else if (ampFactor == 1)
    {
        voltage = X3 * voltage + X2;
    }

/************校准结束****************/
#endif

#ifdef DEBUG_MODE
    //printf("voltage is :  %f v \n", voltage);
#endif

/******自动根据数值大小放大数值***********/
#ifdef USE_AUTO_VALUE
    // v
    fabsVoltage = fabs(voltage);
    if (fabsVoltage - 1.0f > ZERO)
    {
        adjVoltage = voltage;
    }
    // mv
    else if (fabsVoltage - 1.0f < ZERO && fabsVoltage - 0.001f > ZERO)
    {
        adjVoltage = voltage * 1000.0f;
    }
    // uv
    else if (fabsVoltage - 0.001f < ZERO)
    {
        adjVoltage = voltage * 1000000.0f;
    }
#else
    adjVoltage = voltage;
#endif
    /******自动根据数值大小放大数值结束***********/

    AdjVoltage = adjVoltage;

    MultiMeter_ADC_Start();
}
